package com.example.a_java.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.a_java.entity.RepaymentInstallment;
import com.example.a_java.mapper.RepaymentInstallmentMapper;
import com.example.a_java.service.RepaymentInstallmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 还款分期明细Service实现类
 */
@Service
public class RepaymentInstallmentServiceImpl extends ServiceImpl<RepaymentInstallmentMapper, RepaymentInstallment> implements RepaymentInstallmentService {

    @Autowired
    private RepaymentInstallmentMapper repaymentInstallmentMapper;

    @Override
    public List<RepaymentInstallment> getInstallmentsByPlanId(Long planId) {
        return repaymentInstallmentMapper.selectByPlanId(planId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updatePaymentInfo(Long id, LocalDate payDate, BigDecimal payAmount) {
        RepaymentInstallment installment = this.getById(id);
        if (installment == null) {
            throw new RuntimeException("分期明细不存在");
        }

        // 更新还款信息
        installment.setPayDate(payDate);
        installment.setPayAmount(payAmount);
        installment.setStatus("paid");
        installment.setUpdateTime(LocalDateTime.now());

        return this.updateById(installment);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOverdueInfo(Long id, Integer overdueDays, BigDecimal penalty) {
        RepaymentInstallment installment = this.getById(id);
        if (installment == null) {
            throw new RuntimeException("分期明细不存在");
        }

        // 更新逾期信息
        installment.setOverdueDays(overdueDays);
        installment.setPenalty(penalty);
        installment.setStatus("overdue");
        installment.setUpdateTime(LocalDateTime.now());

        return this.updateById(installment);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean generateInstallments(Long planId, BigDecimal loanAmount, BigDecimal interestRate,
                                     Integer totalPeriods, String repaymentMethod, LocalDate startDate) {
        // 清空历史分期明细
        this.lambdaUpdate().eq(RepaymentInstallment::getPlanId, planId).remove();

        // 月利率
        BigDecimal monthRate = interestRate.divide(new BigDecimal("100"), 10, RoundingMode.HALF_UP)
                                         .divide(new BigDecimal("12"), 10, RoundingMode.HALF_UP);

        // 创建分期明细列表
        List<RepaymentInstallment> installments = new ArrayList<>();

        if ("等额本息".equals(repaymentMethod)) {
            // 等额本息计算
            // 每月还款金额 = P × [i × (1 + i)^n] ÷ [(1 + i)^n - 1]
            BigDecimal powN = BigDecimal.ONE.add(monthRate).pow(totalPeriods);
            BigDecimal monthlyPayment = loanAmount.multiply(monthRate.multiply(powN))
                                              .divide(powN.subtract(BigDecimal.ONE), 2, RoundingMode.HALF_UP);

            // 剩余本金
            BigDecimal remainingPrincipal = loanAmount;

            for (int i = 1; i <= totalPeriods; i++) {
                // 应还利息 = 剩余本金 × 月利率
                BigDecimal interest = remainingPrincipal.multiply(monthRate).setScale(2, RoundingMode.HALF_UP);
                
                // 应还本金 = 月还款金额 - 应还利息
                BigDecimal principal = monthlyPayment.subtract(interest).setScale(2, RoundingMode.HALF_UP);
                
                // 最后一期修正，确保本金相加等于贷款金额
                if (i == totalPeriods) {
                    principal = remainingPrincipal;
                    monthlyPayment = principal.add(interest);
                }
                
                // 更新剩余本金
                remainingPrincipal = remainingPrincipal.subtract(principal);
                
                // 计算应还日期
                LocalDate dueDate = startDate.plusMonths(i);
                
                // 创建分期明细
                RepaymentInstallment installment = new RepaymentInstallment();
                installment.setPlanId(planId);
                installment.setPeriod(i);
                installment.setDueDate(dueDate);
                installment.setPrincipal(principal);
                installment.setInterest(interest);
                installment.setAmount(principal.add(interest));
                installment.setPrincipalBalance(remainingPrincipal);
                installment.setStatus("pending");
                installment.setOverdueDays(0);
                installment.setPenalty(BigDecimal.ZERO);
                installment.setCreateTime(LocalDateTime.now());
                
                installments.add(installment);
            }
        } else if ("等额本金".equals(repaymentMethod)) {
            // 等额本金计算
            // 每月本金 = 贷款金额 ÷ 贷款期数
            BigDecimal monthlyPrincipal = loanAmount.divide(new BigDecimal(totalPeriods), 2, RoundingMode.HALF_UP);
            
            // 剩余本金
            BigDecimal remainingPrincipal = loanAmount;
            
            for (int i = 1; i <= totalPeriods; i++) {
                // 应还利息 = 剩余本金 × 月利率
                BigDecimal interest = remainingPrincipal.multiply(monthRate).setScale(2, RoundingMode.HALF_UP);
                
                // 应还本金 = 每月本金
                BigDecimal principal = monthlyPrincipal;
                
                // 最后一期修正，确保本金相加等于贷款金额
                if (i == totalPeriods) {
                    principal = remainingPrincipal;
                }
                
                // 更新剩余本金
                remainingPrincipal = remainingPrincipal.subtract(principal);
                
                // 计算应还日期
                LocalDate dueDate = startDate.plusMonths(i);
                
                // 创建分期明细
                RepaymentInstallment installment = new RepaymentInstallment();
                installment.setPlanId(planId);
                installment.setPeriod(i);
                installment.setDueDate(dueDate);
                installment.setPrincipal(principal);
                installment.setInterest(interest);
                installment.setAmount(principal.add(interest));
                installment.setPrincipalBalance(remainingPrincipal);
                installment.setStatus("pending");
                installment.setOverdueDays(0);
                installment.setPenalty(BigDecimal.ZERO);
                installment.setCreateTime(LocalDateTime.now());
                
                installments.add(installment);
            }
        } else if ("先息后本".equals(repaymentMethod)) {
            // 先息后本计算
            // 每月利息 = 贷款金额 × 月利率
            BigDecimal monthlyInterest = loanAmount.multiply(monthRate).setScale(2, RoundingMode.HALF_UP);
            
            for (int i = 1; i <= totalPeriods; i++) {
                // 最后一期还本金
                BigDecimal principal = (i == totalPeriods) ? loanAmount : BigDecimal.ZERO;
                BigDecimal interest = monthlyInterest;
                
                // 计算应还日期
                LocalDate dueDate = startDate.plusMonths(i);
                
                // 创建分期明细
                RepaymentInstallment installment = new RepaymentInstallment();
                installment.setPlanId(planId);
                installment.setPeriod(i);
                installment.setDueDate(dueDate);
                installment.setPrincipal(principal);
                installment.setInterest(interest);
                installment.setAmount(principal.add(interest));
                installment.setPrincipalBalance(i == totalPeriods ? BigDecimal.ZERO : loanAmount);
                installment.setStatus("pending");
                installment.setOverdueDays(0);
                installment.setPenalty(BigDecimal.ZERO);
                installment.setCreateTime(LocalDateTime.now());
                
                installments.add(installment);
            }
        } else if ("到期一次性还本付息".equals(repaymentMethod)) {
            // 到期一次性还本付息
            // 总利息 = 贷款金额 × 月利率 × 期数
            BigDecimal totalInterest = loanAmount.multiply(monthRate).multiply(new BigDecimal(totalPeriods)).setScale(2, RoundingMode.HALF_UP);
            
            // 计算应还日期
            LocalDate dueDate = startDate.plusMonths(totalPeriods);
            
            // 创建分期明细（只有一期）
            RepaymentInstallment installment = new RepaymentInstallment();
            installment.setPlanId(planId);
            installment.setPeriod(1);
            installment.setDueDate(dueDate);
            installment.setPrincipal(loanAmount);
            installment.setInterest(totalInterest);
            installment.setAmount(loanAmount.add(totalInterest));
            installment.setPrincipalBalance(BigDecimal.ZERO);
            installment.setStatus("pending");
            installment.setOverdueDays(0);
            installment.setPenalty(BigDecimal.ZERO);
            installment.setCreateTime(LocalDateTime.now());
            
            installments.add(installment);
        } else {
            // 默认按等额本息计算
            BigDecimal powN = BigDecimal.ONE.add(monthRate).pow(totalPeriods);
            BigDecimal monthlyPayment = loanAmount.multiply(monthRate.multiply(powN))
                                              .divide(powN.subtract(BigDecimal.ONE), 2, RoundingMode.HALF_UP);

            // 剩余本金
            BigDecimal remainingPrincipal = loanAmount;

            for (int i = 1; i <= totalPeriods; i++) {
                // 应还利息 = 剩余本金 × 月利率
                BigDecimal interest = remainingPrincipal.multiply(monthRate).setScale(2, RoundingMode.HALF_UP);
                
                // 应还本金 = 月还款金额 - 应还利息
                BigDecimal principal = monthlyPayment.subtract(interest).setScale(2, RoundingMode.HALF_UP);
                
                // 最后一期修正，确保本金相加等于贷款金额
                if (i == totalPeriods) {
                    principal = remainingPrincipal;
                    monthlyPayment = principal.add(interest);
                }
                
                // 更新剩余本金
                remainingPrincipal = remainingPrincipal.subtract(principal);
                
                // 计算应还日期
                LocalDate dueDate = startDate.plusMonths(i);
                
                // 创建分期明细
                RepaymentInstallment installment = new RepaymentInstallment();
                installment.setPlanId(planId);
                installment.setPeriod(i);
                installment.setDueDate(dueDate);
                installment.setPrincipal(principal);
                installment.setInterest(interest);
                installment.setAmount(principal.add(interest));
                installment.setPrincipalBalance(remainingPrincipal);
                installment.setStatus("pending");
                installment.setOverdueDays(0);
                installment.setPenalty(BigDecimal.ZERO);
                installment.setCreateTime(LocalDateTime.now());
                
                installments.add(installment);
            }
        }

        // 批量保存分期明细
        return this.saveBatch(installments);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean processOverdue(Long installmentId) {
        RepaymentInstallment installment = this.getById(installmentId);
        if (installment == null) {
            throw new RuntimeException("分期明细不存在");
        }

        // 如果已经还款，不需要处理逾期
        if ("paid".equals(installment.getStatus())) {
            return true;
        }

        // 计算逾期天数
        LocalDate today = LocalDate.now();
        if (today.isAfter(installment.getDueDate())) {
            // 计算逾期天数
            long overdueDays = java.time.temporal.ChronoUnit.DAYS.between(installment.getDueDate(), today);
            
            // 计算罚息，假设罚息率为万分之五每天
            BigDecimal penaltyRate = new BigDecimal("0.0005");
            BigDecimal penalty = installment.getAmount().multiply(penaltyRate).multiply(new BigDecimal(overdueDays)).setScale(2, RoundingMode.HALF_UP);
            
            // 更新逾期信息
            installment.setOverdueDays((int) overdueDays);
            installment.setPenalty(penalty);
            installment.setStatus("overdue");
            installment.setUpdateTime(LocalDateTime.now());
            
            return this.updateById(installment);
        }
        
        return true;
    }

    @Override
    public Map<String, Object> calculatePenalty(Long installmentId, Integer overdueDays) {
        RepaymentInstallment installment = this.getById(installmentId);
        if (installment == null) {
            throw new RuntimeException("分期明细不存在");
        }

        // 罚息率，万分之五每天
        BigDecimal penaltyRate = new BigDecimal("0.0005");
        
        // 计算罚息
        BigDecimal penalty = installment.getAmount().multiply(penaltyRate).multiply(new BigDecimal(overdueDays)).setScale(2, RoundingMode.HALF_UP);
        
        // 组装结果
        Map<String, Object> result = new HashMap<>();
        result.put("principal", installment.getPrincipal());
        result.put("interest", installment.getInterest());
        result.put("amount", installment.getAmount());
        result.put("penaltyRate", penaltyRate);
        result.put("penalty", penalty);
        result.put("totalAmount", installment.getAmount().add(penalty));
        
        return result;
    }
} 